package com.common.retrofit;

import android.os.Environment;
import android.text.TextUtils;

import com.common.config.Constant;
import com.google.gson.Gson;
import com.util_code.utils.AndroidUtils;
import com.util_code.utils.DigestUtils;
import com.util_code.utils.FileUtils;
import com.util_code.utils.NetUtils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;

public class RxRetrofitCache {

    /**
     * @param cacheKey 缓存的Key
     * @param fromNetwork
     * @param isSave       是否缓存
     * @param forceRefresh 是否强制刷新
     * @param <T>
     * @return
     */
    public static <T> Observable<T> load(final String cacheKey, final long expireTime, Observable<T> fromNetwork, boolean forceRefresh, final Type type) {
        Observable<T> fromCache = Observable.create(new ObservableOnSubscribe<T>() {
            @Override
            public void subscribe(ObservableEmitter<T> emitter) throws Exception {
                String cache = getData(cacheKey, expireTime);
                if (!TextUtils.isEmpty(cache)) {
                    T result = new Gson().fromJson(cache, type);
                    emitter.onNext(result);
                } else {
                    emitter.onComplete();
                }
            }
        }).subscribeOn(Schedulers.io());

        fromNetwork = fromNetwork.subscribeOn(Schedulers.newThread())
                .map(new Function<T, T>() {
                    @Override
                    public T apply(T mapResult) throws Exception {
                        if (RxObserver.checkJsonCode(mapResult, false)) {
                            String cache = new Gson().toJson(mapResult);
                            setData(cacheKey, cache);
                        }
                        return mapResult;
                    }
                });

        if (forceRefresh) {
            return fromNetwork;
        } else {
            return Observable.concat(fromCache, fromNetwork)
                    .firstElement()
                    .toObservable();
        }
    }

    public static <T> T loadCacheOnly(String cacheKey, Type type) {
        String cache = getData(cacheKey, Constant.TIME_ONE_HOUR * 10000);
        if (!TextUtils.isEmpty(cache)) {
            T result = null;
            try {
                result = new Gson().fromJson(cache, type);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
            return result;
        }

        return null;
    }

    public static String getData(String key, long expireTime) {
        String result = null;
        File cacheDir;
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            cacheDir = AndroidUtils.getContext().getExternalCacheDir();
            if (cacheDir == null) {
                String packageName = AndroidUtils.getContext().getPackageName();
                cacheDir = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + packageName);
            }
        } else {
            cacheDir = AndroidUtils.getContext().getCacheDir();
        }

        File file = new File(cacheDir, DigestUtils.md5Hex(key));
        if (file.exists() && file.isFile()) {
            long storageTime = System.currentTimeMillis() - file.lastModified();

            boolean online = NetUtils.isConnected();

            // 如果系统时间不对(被调回很久之前),storageTime和expireTime的比较就没有意义了
            // 在这种情况下,如果有网就请求新内容,否则才考虑缓存
            if (online && storageTime < 0) {
                return null;
            }
            // 如果有网的情况下,且缓存已经过期,则返回null
            // 在无网的情况下, 即使过期也返回缓存
            if (online && storageTime > expireTime) {
                return null;
            }
            try {
                result = FileUtils.readString(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 设置字符串为特定key的缓存,保存到本地
     * @param key
     * @param data
     */
    public static void setData(String key, String data) {
        File cacheDir;
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            cacheDir = AndroidUtils.getContext().getExternalCacheDir();
            if (cacheDir == null) {
                String packageName = AndroidUtils.getContext().getPackageName();
                cacheDir = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + packageName);
            }
        } else {
            cacheDir = AndroidUtils.getContext().getCacheDir();
        }

        if (!cacheDir.exists()) {
            cacheDir.mkdirs();
        }

        File file = new File(cacheDir, DigestUtils.md5Hex(key));

        try {
            FileUtils.writeString(file, data);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
